//
//  SEVoiceRecordManager.swift
//  SmartEyeForPatient
//
//  Created by QDSG on 2021/5/6.
//

import UIKit
import AVFoundation

private let kTempWavRecordPath = SEVoiceFilesManager.recoderFilePath(with: "wav_temp_record", fileType: .wav)
private let kTempAmrRecordPath = SEVoiceFilesManager.recoderFilePath(with: "amr_temp_record", fileType: .amr)

class SEVoiceRecordManager: NSObject {
    static let shared = SEVoiceRecordManager()
    
    var recorder: AVAudioRecorder!
    var operationQueue: OperationQueue!
    weak var delegate: SEVoiceRecordDelegate?
    
    fileprivate var startTime: CFTimeInterval! // 录音开始时间
    fileprivate var endTime: CFTimeInterval!   // 录音结束时间
    fileprivate var voiceTimeInterval: NSNumber!
    fileprivate var isFinishRecord: Bool = true
    fileprivate var isCancelRecord: Bool = false
    
    fileprivate override init() {
        self.operationQueue = OperationQueue()
        super.init()
    }
    
    /// 获取录音权限，并初始化录音
    func checkPermissionAndSetupRecord() {
        let session = AVAudioSession.sharedInstance()
        do {
            try session.setCategory(.playAndRecord, mode: .default, options: .duckOthers)
            do {
                try session.setActive(true)
                session.requestRecordPermission { allowed in
                    if !allowed {
                        SEAlert.show(in: UIViewController.current,
                                     title: "无法访问您的麦克风",
                                     message: "请到设置 -> 隐私 -> 麦克风，打开访问权限",
                                     confirmTitle: "去设置") { (_) in
                            SEOpenSettingURL()
                        }
                    }
                }
            } catch let error {
                SELog("无法激活音频会话 \(error.localizedDescription)")
                SEAlert.show(in: UIViewController.current, title: "无法访问您的麦克风", message: error.localizedDescription, confirmHandler: nil)
            }
        } catch let error {
            SELog("设置音频，会话类别时发生错误 \(error.localizedDescription)")
            SEAlert.show(in: UIViewController.current, title: "无法访问您的麦克风", message: error.localizedDescription, confirmHandler: nil)
        }
    }
    
    /// 监听耳机插入的动作
    func checkHeadphones() {
        let currentRoute = AVAudioSession.sharedInstance().currentRoute
        if currentRoute.outputs.count > 0 {
            for description in currentRoute.outputs {
                if description.portType == .headphones {
                    SEHUD.show(message: "耳机已插入")
                    break
                } else {
                    SEHUD.show(message: "耳机已拔出")
                }
            }
        } else {
            SEHUD.showError(message: "检查耳机需要连接到设备.")
        }
    }
    
    /// 开始录音
    func startRecord() {
        isCancelRecord = false
        startTime = CACurrentMediaTime()
        do {
            //基础参数
            let recordSettings: [String: Any] = [
                AVLinearPCMBitDepthKey: NSNumber(value: 16 as Int32), // 线性采样位数  8、16、24、32
                AVFormatIDKey: NSNumber(value: kAudioFormatLinearPCM as UInt32), // 设置录音格式  AVFormatIDKey == kAudioFormatLinearPCM
                AVNumberOfChannelsKey: NSNumber(value: 1 as Int32), // 录音通道数 1 或 2
                AVSampleRateKey: NSNumber(value: 8000.0 as Float),  // 设置录音采样率(Hz) 如：AVSampleRateKey == 8000/44100/96000（影响音频的质量）
            ]
            recorder = try AVAudioRecorder(url: kTempWavRecordPath, settings: recordSettings)
            recorder.delegate = self
            recorder.isMeteringEnabled = true
            recorder.prepareToRecord()
        } catch let error {
            recorder = nil
            SEAlert.show(in: UIViewController.current, title: "初始化录音功能失败", message: error.localizedDescription, confirmHandler: nil)
        }
        self.perform(#selector(readyStartRecord), with: self, afterDelay: 0.0)
    }
    
    /// 准备开始录音
    @objc func readyStartRecord() {
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setCategory(.record)
        } catch let error {
            SEAlert.show(in: UIViewController.current, title: "无法访问您的麦克风", message: error.localizedDescription, confirmHandler: nil)
            return
        }
        
        do {
            try audioSession.setActive(true)
        } catch let error {
            SEAlert.show(in: UIViewController.current, title: "无法访问您的麦克风", message: error.localizedDescription, confirmHandler: nil)
            return
        }
        
        recorder.record()
        let operation = BlockOperation()
        operation.addExecutionBlock(updateMeters)
        operationQueue.addOperation(operation)
    }
    
    /// 更新进度
    func updateMeters() {
        guard let recorder = recorder else { return }
        
        repeat {
            recorder.updateMeters()
            
            voiceTimeInterval = NSNumber(value: NSNumber(value: recorder.currentTime as Double).floatValue as Float)
            let averagePower = recorder.averagePower(forChannel: 0)
            let lowPassResults = pow(10, (0.05 * averagePower)) * 10
            dispatch_async_safely_main_queue {
                self.delegate?.voiceRecordUpdateMetra(lowPassResults)
            }
            
            // 如果大于 60, 停止录音
            if voiceTimeInterval.int32Value > 60 {
                stopRecord()
            }
            
            Thread.sleep(forTimeInterval: 0.05)
            
        } while(recorder.isRecording)
    }
    
    /// 停止录音
    func stopRecord() {
        isFinishRecord = true
        isCancelRecord = false
        endTime = CACurrentMediaTime()
        
        if endTime - startTime < 0.5 {
            NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(readyStartRecord), object: self)
            dispatch_async_safely_main_queue {
                self.delegate?.voiceRecordTooShort()
            }
        } else {
            voiceTimeInterval = NSNumber(value: NSNumber(value: recorder.currentTime as Double).int32Value as Int32)
            if voiceTimeInterval.int32Value < 1 {
                perform(#selector(readyStopRecord), with: self, afterDelay: 0.4)
            } else {
                readyStopRecord()
            }
        }
        operationQueue.cancelAllOperations()
    }
    
    /// 准备停止录音
    @objc func readyStopRecord() {
        recorder.stop()
        recorder = nil
        let audioSession = AVAudioSession.sharedInstance()
        do {
            try audioSession.setActive(false, options: .notifyOthersOnDeactivation)
        } catch let error {
            SELog("error: \(error)")
        }
    }
    
    /// 取消录音
    func cancelRecord() {
        isCancelRecord = true
        NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(readyStartRecord), object: self)
        isFinishRecord = false
        recorder.stop()
        recorder.deleteRecording()
        recorder = nil
        delegate?.voiceRecordCanceled()
    }
    
    /// 删除录音文件
    func deleteRecordFiles() {
        SEVoiceFilesManager.deleteAllRecordingFiles()
    }
}

extension SEVoiceRecordManager: AVAudioRecorderDelegate {
    func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
        if flag && isFinishRecord {
            
        } else {
            if !isCancelRecord {
                delegate?.voiceRecordFailed()
            }
        }
    }
    
    func audioRecorderEncodeErrorDidOccur(_ recorder: AVAudioRecorder, error: Error?) {
        if let error = error {
            SELog("error \(error.localizedDescription)")
            delegate?.voiceRecordFailed()
        }
    }
}
